//zk��׼������
import org.codehaus.groovy.reflection.DoubleKeyHashMap.Entry;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.*;

//jdk��׼������
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;

//�ͻ�����
import publicComponent.*;
import administrationPane.AdminPaneProcessor;
import administrationPane.CommandMgr;
import administrationPane.MainFrameController;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.metainfo.ComponentDefinition;
import org.zkoss.zk.ui.impl.PageImpl;

public class DefaultMainFrameControllerImpl 
extends Tabbox
implements MainFrameController{
	public static final int cacheSize=100;
	public static final String defaultLoadingImgSrc="../Toolbar/loading.gif";
	
	private Tabs tabs=null;
	private Tabpanels panels=null;
	
	public int tabNumber=0;
	public int modelNumber=0;
	public HashMap map=new HashMap();
	public HashMap nameMap=new HashMap();
	
	private AppCache cache;
	private Execution execution;
	private CommandMgr menu;
	
	public void initialize(){
		this.setVisible(false);
		tabs=((Tabs)this.getFellow("ADMIN_TABS"));
		panels=((Tabpanels)this.getFellow("ADMIN_TABPANELS"));
		this.addEventListener("onNotify",new AdminPaneProcessor());
		cache=new AppCache();
		execution=this.getDesktop().getExecution();
		menu=this.getPage().getFellow("ADMIN_WND_MENU");
	}
	
	private void addApp(String name,
						String eventID,
						String preloadingImgSrc,
						String classDef,
						ComponentDefinition def){
		if(!this.isVisible())this.setVisible(true);

		//old code,for test only
		/*
		CustomTab newTab=new CustomTab(name);
		newTab.setClosable(true);
		tabs.appendChild(newTab);
		
		Tabpanel newPanel=new Tabpanel();
		panels.appendChild(newPanel);

		if(eventID != null && !eventID.equals("")){
			this.setAttribute("EVENT_ID", eventID);
			Events.echoEvent("onNotify", this, "");
			newPanel.appendChild(new Image(preloadingImgSrc == null ? defaultLoadingImgSrc : preloadingImgSrc));
		}
		*/
		
		HtmlMacroComponent comp=(HtmlMacroComponent)def.newInstance(this.getPage(), classDef);
		if(!(comp instanceof PublicComponent))
			return;
		else{
			if(((PublicComponent)comp).getTitle() != null)
				name=((PublicComponent)comp).getTitle();
			
			if(((PublicComponent)comp).isInline()){

			//old solution to put them here
			/*
			PublicComponent init=(PublicComponent)comp;
			if(init.isInline()){
				alert(comp.getClass().toString());
				//��ʼ����������
				Window wnd=new Window();
				wnd.setMode("overlapped");
				wnd.setClosable(true);
				wnd.setTitle(name);
				wnd.setWidth("100px");
				wnd.setHeight("100px");
				//��ӵ�ҳ��
				wnd.setPage(this.getPage());
				//��ʼ��Ӧ��
				wnd.appendChild(comp);
				comp.afterCompose();
				wnd.setWidth(comp.getWidth());
				wnd.setHeight(comp.getHeight());
			*/
			
				createInlineApp(name,eventID,preloadingImgSrc,classDef,comp);
			
			}else{
				createStaticApp(name,eventID,preloadingImgSrc,classDef,comp);
			}
		}
			
		//old solution to put it here
		/*
		tabNumber++;
		map.put(newTab,newPanel);
		*/
	}
	
	private void createInlineApp(String name,
								 String eventID,
								 String preloadingImgSrc,
								 String classDef,
								 HtmlMacroComponent comp){

		//��ʼ����������
		CustomWindow wnd=new CustomWindow(this);
		wnd.setMode("overlapped");
		wnd.setClosable(true);
		wnd.setTitle(name);
		wnd.setWidth("100px");
		wnd.setHeight("100px");

		//����comp��onBeforeCreate,�������Ƿ���ӵ�ҳ��
		PublicComponent customComp=(PublicComponent)comp;
		if(!customComp.onBeforeCreate())
			return;
		wnd.setPage(this.getPage());

		//��ʼ��Ӧ��
		wnd.appendChild(comp);
		comp.afterCompose();
		wnd.setWidth(comp.getWidth());
		wnd.setHeight(comp.getHeight());
		
		//����comp��onAfterCreate
		customComp.onAfterCreate();
		
		//���event���Ա�����,�����¼�ͬʱ������
		if(eventID != null && !eventID.equals("")){
			this.setAttribute("EVENT_ID", eventID);
			Events.echoEvent("onNotify", this, "");
			newPanel.appendChild(new Image(preloadingImgSrc == null ? defaultLoadingImgSrc : preloadingImgSrc));
		}
		
		//ά��tabs��map,�Ա�removeApp
		modelNumber++;
		map.put(wnd,comp);
		onCreated(name,wnd,customComp);
	}
	
	private void createStaticApp(String name,
								 String eventID,
								 String preloadingImgSrc,
								 String classDef,
								 HtmlMacroComponent comp){

		//׼��Tab��TabPanel
		CustomTab newTab=new CustomTab(name,this);
		newTab.setClosable(true);
		Tabpanel newPanel=new Tabpanel();
		newPanel.appendChild(comp);

		//����comp��onBeforeCreate�������Ƿ���
		PublicComponent customComp=(PublicComponent)comp;
		if(!customComp.onBeforeCreate())
			return;
		panels.appendChild(newPanel);
		tabs.appendChild(newTab);
		comp.afterCompose();
		//����comp��onAfterCreate

		customComp.onAfterCreate();
		
		//���event���Ա�����,�����¼�ͬʱ������
		if(eventID != null && !eventID.equals("")){
			this.setAttribute("EVENT_ID", eventID);
			Events.echoEvent("onNotify", this, "");
			newPanel.appendChild(new Image(preloadingImgSrc == null ? defaultLoadingImgSrc : preloadingImgSrc));
		}
		
		//ά��tabs��map,�Ա�removeApp
		tabNumber++;
		map.put(newTab,newPanel);
		onCreated(name,newTab,customComp);
	}

	private void onCreated(String appName,Component key,PublicComponent comp){
		List list=nameMap.get(appName);
		if(list == null){
			list=new ArrayList();
			list.add(key);
			nameMap.put(appName, list);
		}else list.add(key);
		((Component)key).setAttribute("APP_NAME", appName);
		
		Map map=(Map)menu.getMap().get(appName);
		comp.setMenuPara(map);
	}
	
	public void createAppWnd(Component cmp){
		if(!(cmp instanceof Menuitem) && !(cmp instanceof Fisheye))
			return;
		else{
			String name=cmp.getAttribute("APP_NAME");
			String url=cmp.getAttribute("MACRO_URI");
			String eventStr=cmp.getAttribute("APP_EVENT_NAME");
			String classPath=cmp.getAttribute("CLASS_PATH");
			String img=cmp.getAttribute("APP_LOADING_IMG");
			if(name == null || name.equals("") || 
			   url == null || url.equals(""))
				return;
			
			ComponentDefinition def=getDef(cmp);

			//Ϊ��������
			if(def == null){
				alert("error,MacroDefinition is null");
				return;
			}else addApp(name,eventStr,img,classPath,def);
		}
	}
	
	private ComponentDefinition getDef(Component cmp){
		String name=cmp.getAttribute("APP_NAME");
		String url=cmp.getAttribute("MACRO_URI");
		String classPath=cmp.getAttribute("CLASS_PATH");
		ComponentDefinition tempDef=cache.findApp(name);
		if(tempDef == null){
			tempDef=this.getPage()
						.getLanguageDefinition()
						.getMacroDefinition(name,url,false,null);
			if(classPath != null && !classPath.equals(""))
				tempDef.setImplementationClass(classPath);
			cache.put(name,tempDef);
		}
		return tempDef;
	}
	
	/*
	public boolean removeApp(Component comp){
	
		//old code,for deleting app in tab mode only
		
		//if(tabNumber == 0)return;
		//if(--tabNumber == 0)
		//	this.setVisible(false);
		
		//Tabpanel panel=map.get(comp);
		//Iterator itr=panel.getChildren().iterator();
		//while(itr.hasNext()){
		//	Component next=itr.next();
		//	if(next instanceof PublicComponent)
		//		((PublicComponent)next).onClose();
		//}
		
		
		PublicComponent customComp=(PublicComponent)comp.getChildren().get(0);
		if(!customComp.onBeforeClose())
			return false;
		
		if(customComp.isInline()){
			modelNumber--;
			map.remove(cmp);
			customComp.onAfterClose();
		}else{
			tabNumber--;
			map.remove(cmp);
			customComp.onAfterClose();
		}
		
		return true;
	}
	*/
	
	public boolean processCommand(String appName,String commandName,Component invoker){
		if(commandName.equals("CREATE"))
			createAppWnd(invoker);
		else{
			List list=(List)nameMap.get(appName);
			if(list != null){
				Iterator itr=list.iterator();
				while(itr.hasNext()){
					Component next=(Component)itr.next();
					PublicComponent comp;
					
					//����Ƿ�Ϊinline��ʼ��comp
					if(next instanceof Window)
						comp=((PublicComponent)next.getChildren().get(0));
					else
						comp=((PublicComponent)((Tabpanel)processor.map.get(this)).getChildren().get(0))
															  .processCommand(commandName);
					
					//���comp�Ƿ�֧�ָ�command
					if(comp.getCommandList().contains(commandName))
						comp.processCommand(commandName);
				}//end while
			}//end if
		}//end outter if
	}
	
	private class CustomTab extends Tab{
		private DefaultMainFrameControllerImpl processor;
		
		public CustomTab(String name,DefaultMainFrameControllerImpl processor){
			super(name);
			this.processor=processor;
		}
		
		//old code,cause problem with new version of ZK
		
		public void onClose(){
			PublicComponent macro=(PublicComponent)((Tabpanel)processor.map.get(this)).getChildren().get(0);
			if(!macro.onBeforeClose())
				return;
			else{
				processor.map.remove(this);

				List list=processor.nameMap.get(this.getAttribute("APP_NAME"));
				list.remove(this);

				processor.tabNumber--;
				macro.onAfterClose();
				
				if(tabNumber == 0)
					this.getParent().getParent().setVisible(false);
				super.onClose();
			}
		}
	}
	
	private class AppCache{
		private HashMap cacheMap;
		private TreeMap frequencyMap;
		
		public AppCache(){
			cacheMap=new HashMap();
			frequencyMap=new TreeMap();
		}
		
		public ComponentDefinition findApp(String name){
			ComponentDefinition def=(ComponentDefinition)cacheMap.get(name);
			if(def != null){
				int lastFreq=((Integer)(frequencyMap.get(name))).intValue();
				lastFreq++;
				frequencyMap.put(name, new Integer(lastFreq));
			}
			return def;
		}
		
		public boolean put(String name,ComponentDefinition def){
			if(cacheMap.get(name) != null)
				return false;
			else{
				if(frequencyMap.size() < DefaultMainFrameControllerImpl.cacheSize){
					frequencyMap.put(name, new Integer(1));
					cacheMap.put(name,def);
				}else{
					Map.Entry min;
					Iterator itr=frequencyMap.entrySet().iterator();
					while(itr.hasNext()){
						Map.Entry entry=itr.next();
						if(min == null)min=entry;
						else if(((Integer)min.getValue()).intValue() < ((Integer)entry.getValue()).intValue())
							min=entry;
					}
					cacheMap.remove(min.getKey());
					frequencyMap.remove(min.getKey());
					cacheMap.put(name, def);
					frequencyMap.put(name, new Integer(1));
				}
			}
			return true;
		}
	}
	
	private class CustomWindow extends Window{
		private DefaultMainFrameControllerImpl processor;
		
		public CustomWindow(DefaultMainFrameControllerImpl processor){
			super();
			this.processor=processor;
		}
		
		//old code,cause problem with new version of ZK
		
		public void onClose(){
			PublicComponent macro=(PublicComponent)processor.map.get(this);
			if(!macro.onBeforeClose())
				return;
			else{
				processor.map.remove(this);

				List list=processor.nameMap.get(this.getAttribute("APP_NAME"));
				list.remove(this);

				processor.modelNumber--;
				macro.onAfterClose();
				super.onClose();
			}
		}
	}
}